﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Poi.NET.util
{
    /**
     * representation of an integer (32-bit) field at a fixed location
     * within a byte array
     *
     * @author Marc Johnson (mjohnson at apache dot org
     */

    public class IntegerField : FixedField
    {
        private int _value;
        private readonly int _offset;

        /**
         * construct the IntegerField with its offset into its containing
         * byte array
         *
         * @param offset of the field within its byte array
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is
         *            negative
         */
        public IntegerField(int offset)
        {
            if (offset < 0)
            {
                throw new IndexOutOfRangeException("negative offset");
            }
            _offset = offset;
        }

        /**
         * construct the IntegerField with its offset into its containing
         * byte array and initialize its value
         *
         * @param offset of the field within its byte array
         * @param value the initial value
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is
         *            negative
         */
        public IntegerField(int offset, int value)
        {
            if (offset < 0)
            {
                throw new IndexOutOfRangeException("negative offset");
            }
            _offset = offset;

            set(value);
        }

        /**
         * Construct the IntegerField with its offset into its containing
         * byte array and initialize its value from its byte array
         *
         * @param offset of the field within its byte array
         * @param data the byte array to read the value from
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is not
         *            within the range of 0..(data.length - 1)
         */

        public IntegerField(int offset, byte[] data)
        {
            if (offset < 0)
            {
                throw new IndexOutOfRangeException("negative offset");
            }
            _offset = offset;

            readFromBytes(data);
        }

        /**
         * construct the IntegerField with its offset into its containing
         * byte array, initialize its value, and write the value to a byte
         * array
         *
         * @param offset of the field within its byte array
         * @param value the initial value
         * @param data the byte array to write the value to
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is
         *            negative or too large
         */

        public IntegerField(int offset, int value, byte[] data)
        {
            if (offset < 0)
            {
                throw new IndexOutOfRangeException("negative offset");
            }
            _offset = offset;

            set(value, data);
        }

        /**
         * get the IntegerField's current value
         *
         * @return current value
         */

        public int get()
        {
            return _value;
        }

        /**
         * set the IntegerField's current value
         *
         * @param value to be set
         */

        public void set(int value)
        {
            _value = value;
        }

        /**
         * set the IntegerField's current value and write it to a byte
         * array
         *
         * @param value to be set
         * @param data the byte array to write the value to
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is too
         *            large
         */

        public void set(int value, byte[] data)
        {
            _value = value;
            writeToBytes(data);
        }

        /* ********** START implementation of FixedField ********** */

        /**
         * set the value from its offset into an array of bytes
         *
         * @param data the byte array from which the value is to be read
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is too
         *            large
         */

        public void readFromBytes(byte[] data)
        {
            _value = LittleEndian.getInt(data, _offset);
        }

        /**
         * set the value from an InputStream
         *
         * @param stream the InputStream from which the value is to be
         *               read
         *
         * @exception BufferUnderrunException if there is not enough data
         *            available from the InputStream
         * @exception IOException if an IOException is thrown from reading
         *            the InputStream
         */

        public void readFromStream(Stream stream)
        {
            _value = LittleEndian.readInt(stream);
        }

        /**
         * write the value out to an array of bytes at the appropriate
         * offset
         *
         * @param data the array of bytes to which the value is to be
         *             written
         *
         * @exception ArrayIndexOutOfBoundsException if the offset is too
         *            large
         */

        public void writeToBytes(byte[] data)
        {
            LittleEndian.putInt(data, _offset, _value);
        }

        /**
         * return the value as a String
         *
         * @return the value as a String
         */

        public String toString()
        {
            return _value.ToString();
        }

        /* **********  END  implementation of FixedField ********** */
    }   // end public class IntegerField
}
